package pl.prv.polanie.client.widgets.schedule;

import pl.prv.polanie.client.Planner;
import pl.prv.polanie.client.dto.CSPreferenceDTO;
import pl.prv.polanie.client.dto.CSPreferenceTypeDTO;
import pl.prv.polanie.client.dto.CSVPreferenceDTO;
import pl.prv.polanie.client.dto.CSVPreferenceTypeDTO;
import pl.prv.polanie.client.dto.LecturerPreferencesDTO;
import pl.prv.polanie.client.dto.PreferenceDTO;
import pl.prv.polanie.client.filemanager.Tooltip;
import pl.prv.polanie.client.model.CacheService;
import pl.prv.polanie.client.model.ServiceHolder;
import pl.prv.polanie.client.model.ViewDataProvider;
import pl.prv.polanie.client.widgets.schedule.custom.PreferenceTypeChooser;
import pl.prv.polanie.client.widgets.schedule.widgets.DraggableElement;
import pl.prv.polanie.client.widgets.schedule.widgets.DraggableZone;
import pl.prv.polanie.client.widgets.utils.Borders;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventPreview;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.MouseListenerAdapter;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;

public class LecturerPreferences extends DraggableElement {
	
	private static final String STYLE_EVENT = "my-LecturerPreferences";

	private static final String STYLE_EVENT_HANDLER = "my-Event-handler";
	private static final String STYLE_EVENT_PROPERTY = "my-Event-property";
	
	private static final String STYLE_EVENT_REMOVE_ICON = "my-Event-removeIcon";
	private static final String STYLE_EVENT_RESIZE_ICON = "my-Event-resizeIcon";

	
	
	//user can catch for it and start dragging
	private final HTML handlerHTML = new HTML("");
	
	private boolean resizingModeOn = false; 

	//true, gdy uzytkownik zaczal przeciagac LP - az do upuszczenia elementu
	private boolean handlerHTMLafterOnMouseDown = false;
	//true, gdy uzytkownik po chwyceniu LP przeciagnal go o dowolna odleglosc
	private boolean hasBeenMoved = false;
	
	
	private boolean wasAttached = false;
	
	/** true, gdy kursor zjechal z LP, false gdy jest nad closeIcon */
	private boolean hidingCloseIconPossible = true;
	
	/**
	 * wskazuje czy zajecia odbywaja sie:
	 * 	co tydzien = 0
	 * 	w tygodnie parzyste = 1
	 *  w tygodnie nieparzyste = 2
	 */ 
//	private int allOrEvenOrOdd = 0;
	
	private boolean draggingInProgress = false;

	/** czas, po ktorym zostana ukrtye kontrolki do usuwania/edycji lecturerPreferences
	 * po zjechaniu z kontrolki */
	int TIME_TO_HIDE_EDIT_WIDGETS = 200;

	
	
	private LecturerPreferencesDTO dto = null;
	
	private PreferenceDTO preferenceDTO = null;
	
	private CSPreferenceDTO csPreferenceDTO = null;
	
	private HTML eventProperty1HTML;  
	private HTML eventProperty2HTML;
	
	/**
	 * Uchwyt do zmiany rozmiaru LP. 
	 */
	private Image removeIconImage;
	private HTML resizeHandlerHTML;
	
	private static final String removeSubjectEventImageURL = "images/customTabPanel_close.png";

	
	/**
	 * Wsplrzedna igrekowa okreslajaca miejsce klikniecia podczas rozpoczecia zmiany rozmiaru LP.
	 */
	private int resizingInitialY = 0;
	
	
	/** Timer wlaczajacy z opznieniem chowanie kontroelk do usuwania i edycji LP. */
	private Timer timer = null;
	
	
	//wspolrzedna subject eventa na formatce dnia 
	private int y; 
	
	
	private int calendarDayWidth = 0;
	
	
	private AbsolutePanel mainAP = new AbsolutePanel();
	
	
	/**
	 * EP uzywany podczas tworzenia (rozciagania) LecturePreferences.
	 */
	private EventPreview resizingWhileCreatingEP = new EventPreview() {
		public boolean onEventPreview(Event event) {
//			Planner.log("LecturerPreferences.resizingWhileCreatingEP EVENT: " + DOM.eventGetTypeString(event));
			
			switch (DOM.eventGetType(event)) {
			case Event.ONMOUSEMOVE:
				if (DOM.eventGetButton(event) == Event.BUTTON_LEFT) {
//					Planner.log("LecturerPreferences.resizingWhileCreatingEP onMouseMove ButtonLeft");
					int x = DOM.eventGetClientX(event);
					
					/**
					 * Sprawdzac y i rozciagac lecturerPreferences.
					 */
					
					DraggableZone parentDZ = getParentDraggableZone();

					//Planner.log("Wobec DZa mamy eventa na yy " + yy);
					int yy = ScheduleUtil.getEventYOverWidget(parentDZ, event);
					
					int lpWidgetTop = parentDZ.getWidgetTop(LecturerPreferences.this);
					
					int proposedHeight = yy - lpWidgetTop + resizingInitialY;
					proposedHeight = proposedHeight/9 * 9;
					
					if (proposedHeight > 0) {
						if (parentDZ.isResizingPossible(lpWidgetTop, proposedHeight)) {
							setHeight(proposedHeight + "px");
						} else {
//							Planner.log("LecturerPreferences.resizingWhileCreatingEP.onMouseMove():  " + "nowa pozycja ZLA" ); 
						}
					}
					
				} else {
					setResizingModeOff();
				}
				break;
				
			case Event.ONMOUSEUP:
				setResizingModeOff();
				return false;
			}
			return false;
		}
		
	};
	
	/**
	 * EP nasluchujacy eventow myszy przy najechaniu na lecturerPreference.
	 */
	private final EventPreview whileDraggingOverEP = new EventPreview() {
		public boolean onEventPreview(Event event) {
//			Planner.log("LecturerPreferences.resizingWhileCreatingEP EVENT: " + DOM.eventGetTypeString(event));
			
			switch (DOM.eventGetType(event)) {
			case Event.ONMOUSEMOVE:
				if (!ScheduleUtil.eventOverWiget(handlerHTML, event)) {
					DOM.removeEventPreview(whileDraggingOverEP);
					hideEditIcons();
				}
				break;
			
			}
			return true;
		}
	};

	/**
	 * Pokazuje kontrolki na lecturerPreferences sluzace do zmiany rozmiaru/usuwania.
	 */
	private void showEditIcons() {
		if (timer != null) {
			timer.cancel();
		}
		
		if (removeIconImage == null) {
			removeIconImage = new Image(removeSubjectEventImageURL){
//				@Override
				public void onBrowserEvent(Event event) {
					super.onBrowserEvent(event);
					
					switch (DOM.eventGetType(event)) {
						case Event.ONMOUSEOUT:
							if (!ScheduleUtil.eventOverWiget(LecturerPreferences.this, event)) {
								Planner.hideToolTip();
								hideCloseIcon();
							}
							break;
					}
				}
			};
			removeIconImage.setStyleName(STYLE_EVENT_REMOVE_ICON);
			removeIconImage.setWidth(14+"px");
			removeIconImage.setHeight(20 + "px");
			removeIconImage.addClickListener(new ClickListener() {
				public void onClick(Widget sender) {
					removeLecturerPreference();
				}
			});
			mainAP.add(removeIconImage);
		}
		
		if (resizeHandlerHTML == null) {
			resizeHandlerHTML = new HTML("<div><center><img src='./widgets-images/sorted_desc.png' /></center></div>");
			resizeHandlerHTML.addMouseListener(new MouseListenerAdapter() {
				@Override
				public void onMouseLeave(Widget sender) {
					super.onMouseLeave(sender);
//					if (!ScheduleUtil.eventOverWiget(LecturerPreferences.this, event)) {
						Planner.hideToolTip();
						hideCloseIcon();
//					}
				}
				@Override
				public void onMouseDown(Widget sender, int x, int y) {
//					super.onMouseDown(sender, x, y);
//					setResizingModeOn();
					Planner.log("LecturerPreferences.resizeHandlerHTML.onMouseDown() resizingInitialY " + y );
					resizingInitialY = y;
					
					boolean whileCreating = false;
					setResizingModeOn(whileCreating);
				}

			});
			
			
			resizeHandlerHTML.setStyleName(STYLE_EVENT_RESIZE_ICON);
			resizeHandlerHTML.setHeight("14px");
			resizeHandlerHTML.setWidth(calendarDayWidth + "px");
			mainAP.add(resizeHandlerHTML);
		}
	}
	
	/**
	 * Usuwa kontrolki na lecturerPreferences sluzace do zmiany rozmiaru/usuwania.
	 */
	private void hideEditIcons() {
		if (timer != null) {
			timer.cancel();
		}
		
		if (removeIconImage != null) {
			mainAP.remove(removeIconImage);
			removeIconImage = null;
		}

		if (resizeHandlerHTML != null) {
			mainAP.remove(resizeHandlerHTML);
			resizeHandlerHTML = null;
		}
	}
	
	
	/**
	 * Wlacza tryb nasluchiwania na eventy myszy podczas zmiany rozmiaru LecturerPreferences.
	 */
	public void setResizingModeOn(boolean whileCreating) {
//		Planner.log("LecturerPreferences.setResizingModeOn()");
		if (whileCreating) {
			resizingInitialY = 0;
		}
			getParentDraggableZone().getParentSchedule().setActiveLecturerPreferences(LecturerPreferences.this);
//		}
		DOM.addEventPreview(resizingWhileCreatingEP);
		resizingModeOn = true;
	}
	
	/**
	 * Wylacza tryb nasluchiwania na eventy myszy podczas zmiany rozmiaru LecturerPreferences.
	 */
	public void setResizingModeOff() {
		getParentDraggableZone().getParentSchedule().setActiveLecturerPreferences(null);
		DOM.removeEventPreview(resizingWhileCreatingEP);
		resizingModeOn = false;
//		Planner.log("LecturerPreferences.setResizingModeOff()");


		if (getOffsetHeight() == 0) {
			getParentDraggableZone().remove(LecturerPreferences.this);
			//Planner.log("LecturerPreferences.resizingWhileCreatingEP.onEventPreview() usuwam LP o wysokosci 0."); 
		} else {
			saveLecturerPreferenceIfChanged();
		}
	}
	
	private void hideCloseIcon() {
//		if (timer == null) {
//			timer = new Timer() {
////			@Override
//				public void run() {
//					if (removeIconHTML != null) {
//						mainAP.remove(removeIconHTML);
//						removeIconHTML = null;
//					}
//					if (resizeHandlerHTML != null) {
//						mainAP.remove(resizeHandlerHTML);
//						resizeHandlerHTML = null;
//					}
//				}
//			};
//		} 
//		timer.schedule(TIME_TO_HIDE_EDIT_WIDGETS);
	}
	
	public LecturerPreferences(CSPreferenceDTO dto, int calendarDayWidth, ScheduleView scheduleView) {
		this.calendarDayWidth = calendarDayWidth;
		this.csPreferenceDTO = dto;
		CSVPreferenceDTO csvp = ViewDataProvider.getCSVPreference(dto);
		this.y = ScheduleUtil.convertFromStartTimeToPixels(dto.getStartTime().intValue(), CacheService.isFullTimeSemesterSelected()); 
		setupEventPropertiesHTML(csvp);
		setupHandlerHTML(scheduleView);
		setupMainAP();
		
		//ustawienie koloru LP
		DOM.setStyleAttribute(mainAP.getElement(), "backgroundColor", csvp.getPreferenceTypeColor());

		
		initWidget(mainAP);
		setStyleName(STYLE_EVENT);
		
		
		Borders.addGrayDashedBorders(mainAP);
		
		int height = ScheduleUtil.convertFromDurationToPixels(dto.getDuration().intValue(), CacheService.isFullTimeSemesterSelected());
//		Planner.log("LecturerPreferences.kostr() duration: " + dto.getDuration().intValue() + ", height " + height);
		setHeight(height + "px");
	}
	
	
	
	@Override
	protected void onAttach() {
		super.onAttach();
		if (!wasAttached) {
			wasAttached = true;
			
			if (preferenceDTO != null || dto != null || csPreferenceDTO != null) {
				setAll();
			}
		}
	}

	private void setupEventPropertiesHTML(CSVPreferenceDTO lp) {
		eventProperty1HTML = new HTML(""+lp.getPreferenceTypeName());
		eventProperty1HTML.setStyleName(STYLE_EVENT_PROPERTY);
		eventProperty2HTML = new HTML(""+lp.getLecturer());
		eventProperty2HTML.setStyleName(STYLE_EVENT_PROPERTY);
	}	
	
	
	private void setupHandlerHTML(ScheduleView scheduleView) {
		handlerHTML.setStyleName(STYLE_EVENT_HANDLER);
		handlerHTML.setWidth(calendarDayWidth+"px");
		handlerHTML.setHeight(54+"px");
		
		//dodanie mozliwosci edycji preferencji (tylko w widoku lecturer_preferences)
		if (scheduleView == ScheduleView.LECTURER_PREFERENCES) {
			
			handlerHTML.addMouseListener(new MouseListenerAdapter() {
//			@Override
				public void onMouseDown(Widget sender, int x, int y) {
					super.onMouseDown(sender, x, y);
//				Planner.log("LecturerPreferences.handlerHTML.onMouseDown()");
//				int yy = y;
					try {
						
						handlerHTMLafterOnMouseDown = true;
						hasBeenMoved = false;
						
						Schedule ps = getParentDraggableZone().getParentSchedule();
						Planner.log("przeciagam LP w schedule " + ps);
						getParentDraggableZone().getParentSchedule().setActiveLecturerPreferences(LecturerPreferences.this);
						
						Planner.log("LecturerPreferences.setupHandlerHTML.onMouseDown() " + "przeciagam: " + csPreferenceDTO.toLabel() ); 
						
						setDraggingOn(y);
						draggingInProgress = true;
						Planner.hideToolTip();
					} catch (Exception e) {
						Planner.log("LecturerPreferences.ONMOUSEDOWN WYJATEK " + e);
					}
				}
				
//			//@Override
//			public void onMouseUp(Widget sender, int x, int y) {
//				super.onMouseUp(sender, x, y);
//			}
				
//			@Override
				public void onMouseEnter(Widget sender) {
					super.onMouseEnter(sender);
//				Planner.log("LecturerPreferences.handlerHTML.onMouseEnter()");
					
					showEditIcons();
					
					DOM.addEventPreview(whileDraggingOverEP);
					//		DOM.removeEventPreview(creatingEP);
					//TODO usunalem 10:01
//				DOM.addEventPreview(editEP);
				}
			});
			
		}
		
//		handlerHTML.addClickListener(new ClickListener(){
//			public void onClick(Widget sender) {
//				int left = sender.getAbsoluteLeft() + sender.getOffsetWidth();
//				int top = sender.getAbsoluteTop() + sender.getOffsetHeight();
//
//				showEditWidget(left, top);
//			}
//		});

	}
	
//	@Override
	protected void runOnMouseMove() {
		super.runOnMouseMove();
		
		hasBeenMoved = true;
	}
	
	@Override
	protected void runOnDrop(int left, int top) {
		super.runOnDrop(left, top);
		
		LecturerPreferences lp = (LecturerPreferences) this;
//			Planner.log("DEEEE " + lp.getOffsetHeight());
		try {
			DraggableZone dz = lp.getParentDraggableZone();
			
			if (lp.getOffsetHeight() == 0) {
//					Planner.log("DZ duration => 0 wiec usuwam");
				dz.remove(lp);
			} else {
//					Planner.log("DZ duration => " + lp.getDto().getDuration().intValue());
			}
			
			lp.getParentDraggableZone().getParentSchedule().setActiveLecturerPreferences(null);
			
		} catch (Exception e) {
			Planner.log("DraggableElement.runOnDrop() nie zostal podpiety do zadnego DZ: " + e); 
		}
		
		
		
		
		
		
		
		if (!hasBeenMoved) {
			showEditWidget(left, top);
		}
		
		saveLecturerPreferenceIfChanged();
	}

	
	/**
	 * Zapisuje lecturerPreference, gdy ulegla ona zmianie. Metoda uzywana po przeciagnieciu subjectEventa.
	 */
	private void saveLecturerPreferenceIfChanged() {
		final CSPreferenceDTO csp = csPreferenceDTO;
		
		//before 
		//CSPreferenceDTO csp = csPreferenceDTO;
		long oldStartTime = csp.getStartTime().longValue();
		long oldDurationTime = csp.getDuration().longValue();
		long oldCalendarDayID = csp.getCalendarDayID();
		
		
		//mapowanie polozenia w kontrolce draggable zone (zawartej w dniu)
		//na start time i duration
		DraggableZone parentDZ = getParentDraggableZone();
		Day parentDay = parentDZ.getParentDay();
		
		int top = parentDZ.getWidgetTop(this);
		int height = getOffsetHeight();
		
		Planner.log("LecturerPreferences.saveLecturerPreferenceIfChanged: "
				+ " PX OD GORY " + top);
		
		int newStartTime = ScheduleUtil.convertFromPixelsToStartTime(top, CacheService.isFullTimeSemesterSelected());
		Planner.log("LecturerPreferences.saveLecturerPreferenceIfChanged: "
				+ " START TIME => " + newStartTime);
		int newDuration = ScheduleUtil.convertFromPixelsToDuration(height, CacheService.isFullTimeSemesterSelected());
		long newCalendarDayID = parentDay.getCalendarDayDTO().getId();
		
//		GWT.log("SubjectEvent.saveSubjectEvent wyliczono startTime: " + startTime, null);
		//jesli polozenie LP uleglo zmianie
		if (
				oldStartTime != newStartTime
				|| oldDurationTime != newDuration 
				|| oldCalendarDayID != newCalendarDayID
			) {
		
			csp.setStartTime(new Integer((int) newStartTime));
			csp.setDuration(new Integer((int) newDuration));
			csp.setCalendarDayID(newCalendarDayID);
			
			
			Planner.log("LecturerPreferences.saveLecturerPreferenceIfChanged(): LP zmienione -> zapis do bazy"); 
			AsyncCallback callback = new AsyncCallback(){
				public void onFailure(Throwable caught) {
					Planner.log("SubjectEvent.saveLecturerPreferences ONFAILURE blad przy probie zapisu");
				}
				public void onSuccess(Object result) {
					long lpID = ((Long)result).longValue();
					LecturerPreferences.this.csPreferenceDTO.setId(lpID);
					Planner.log("SubjectEvent.saveLecturerPreferences ONSUCCESS ustawilem id " + lpID);
				}
			};
			ServiceHolder.get().savePreference(csp, callback);
		}
	}
	
	/**
	 * Zapisuje lecturerPreference, gdy ulegla ona zmianie. Metoda uzywana po zmianie  preferenceType w menu kontekstowym.
	 */
	private void saveLecturerPreferenceIfPreferenceTypeChanged(final CSPreferenceTypeDTO dto) {
		final CSPreferenceDTO csp = csPreferenceDTO;
		
		long oldPreferenceTypeID = csp.getPreferenceTypeID(); 
		long newPreferenceTypeID = dto.getId();

		Planner.log("LecturerPreferences.saveLecturerPreferenceIfPreferenceTypeChanged(): nowe dto: " + dto);
		
		if (oldPreferenceTypeID != newPreferenceTypeID) {
			csp.setPreferenceTypeID(newPreferenceTypeID);
			
			Planner.log("LecturerPreferences.saveLecturerPreferenceIfPreferenceTypeChanged(): LP (preferenceType) zmienione -> zapis do bazy"); 
			AsyncCallback callback = new AsyncCallback(){
				public void onFailure(Throwable caught) {
					Planner.log("SubjectEvent.saveLecturerPreferenceIfPreferenceTypeChanged ONFAILURE blad przy probie zapisu");
				}
				public void onSuccess(Object result) {
					long lpID = ((Long)result).longValue();
					LecturerPreferences.this.csPreferenceDTO.setId(lpID);
					String newColor = ((CSVPreferenceTypeDTO)ViewDataProvider.getCSVPreferenceType(dto)).getColor();
					DOM.setStyleAttribute(mainAP.getElement(), "backgroundColor", newColor);
					Planner.log("SubjectEvent.saveLecturerPreferences ONSUCCESS ustawilem id " + lpID);
				}
			};
			ServiceHolder.get().savePreference(csp, callback);

		}
		
	}
	
	private void removeLecturerPreference() {
		final CSPreferenceDTO csp = csPreferenceDTO;
		final long pID = csp.getId();
		
		AsyncCallback callback = new AsyncCallback(){
			public void onFailure(Throwable caught) {
				Planner.log("SubjectEvent.removeLecturerPreference ONFAILURE blad przy probie zapisu");
			}
			public void onSuccess(Object result) {
				//LecturerPreferences.this.csPreferenceDTO.setId(lpID);
				Planner.log("SubjectEvent.removeLecturerPreference ONSUCCESS usunieto id " + pID);
				getParentDraggableZone().remove(LecturerPreferences.this);
			}
		};
		ServiceHolder.get().removePreference(csp, callback);
	}
	

	/**
	 * Displays widget, in which we can edit preference.
	 * @param left
	 * @param top
	 */
	private void showEditWidget(int left, int top) {
		
		boolean autoHide = true;
		boolean modal = true;
		final PopupPanel pp = new PopupPanel(autoHide, modal);
		
		Widget w = generateHintsWidget();
		
		final Tooltip t = new Tooltip(w);
		pp.setWidget(t);
		
		pp.setPopupPosition(left, top);
		pp.show();
	}
	
	
	private Widget generateHintsWidget() {

		final PreferenceTypeChooser ptc = new PreferenceTypeChooser(){
			@Override
			protected void runOnSelectedItem() {
				super.runOnSelectedItem();
				Planner.log("LecturerPreferences.generateHintsWidget(): " + this.getSelectedItemDTO());
				saveLecturerPreferenceIfPreferenceTypeChanged(this.getSelectedItemDTO());
				
				getParent().getParent().removeFromParent();
			}
		};

		return ptc;  
	}
	
	private void setAll() {
		mainAP.setWidgetPosition(eventProperty1HTML, 0, 0);
		mainAP.setWidgetPosition(eventProperty2HTML, 0, 10);
	}
	
	protected void onKeyDown(char c, boolean ctrlPressed) {
		super.onKeyDown(c, ctrlPressed);
		
		if (dto != null) {
			setAll();
		}
	}
	
	protected void onMouseMove(int x, int y) {
		super.onMouseMove(x, y);
		draggingInProgress = false;
	}
	
	private void setupMainAP() {
		
		mainAP.setWidth(calendarDayWidth+"px");
		
		mainAP.add(eventProperty1HTML,-1,-1);
		mainAP.add(eventProperty2HTML,-1,-1);
		
		mainAP.add(handlerHTML, 0, 0);
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}
	
	public DraggableZone getParentDraggableZone() {
		return (DraggableZone)getParent();
	}
	

	@Override
	public void setHeight(String height) {
		super.setHeight(height);
		handlerHTML.setHeight(height);
	}

	public LecturerPreferencesDTO getDto() {
		return dto;
	}

	public void setDto(LecturerPreferencesDTO dto) {
		this.dto = dto;
	}

	public CSPreferenceDTO getCsPreferenceDTO() {
		return csPreferenceDTO;
	}

}
